﻿/***************************************************/
/*** file:IMServer.cs                            ***/
/*** date:2010-08-07                             ***/
/*** author:huas                                 ***/
/*** function:implement common server by TCP     ***/
/*** description:异步接收，同步发送模型             ***/
/***************************************************/



using System;
using System.Collections.Generic;
using System.Collections;
using System.Linq;
using System.Text;
using System.Net;
using System.Net.Sockets;
using System.Threading;
using System.IO;
using System.Runtime.InteropServices;
using IM.Common;
using IM.Logic;

namespace IM.Net
{
    enum RunFlag
    {
        RUNFLAG_RUNING,
        RUNFLAG_STOP,
        RUNFLAG_INIT,
    }

    class IMServer : IHanleSink
    {
        private SocketInfo[]                m_socketInfos;
        private SocketAsyncEventArgsPool    m_recvArgsPool;
        private SocketAsyncEventArgsPool    m_sendArgsPool;

        private RunFlag                     m_runFlag;

        private Socket                      m_listenSocket;
        private IPEndPoint                  m_localEndPoint;

        private UInt32                      m_nClientSocketCount;
        private Semaphore                   m_acceptSemaphore;

        private int                         m_nFreeHeaderIndex; //空闲链头指针
        private int                         m_nUsedHeaderIndex;  //使用链头指针
        private ConfigInfo                  m_configInfo;
        private int                         m_nBeginSocketIndex;

        private DateTime                    m_lastCheckTime = DateTime.Now;

        private IHanleServer                m_handleServer;


        public IMServer()
        { 
        }

        private bool LoadConfig()
        {
            m_configInfo.m_nConnTimeout      = 30;
            m_configInfo.m_nListenAddr       = IPAddress.Parse("127.0.0.1");
            m_configInfo.m_nListenPort       = 5099;
            m_configInfo.m_nMaxClientLen     = 10240;
            m_configInfo.m_nMaxConnClients   = 5000;
            m_configInfo.m_nSocketTimeout    = 30000;
            m_configInfo.m_nTcpBufLen        = 10240;
            m_configInfo.m_nWriteStatTime    = 50000;
            m_configInfo.m_nSocketRecvBufLen = 1024 * 10;
            m_configInfo.m_nSocketSendBufLen = 1024 * 10;
            m_configInfo.m_nCheckSocketTime  = 1000;
            m_configInfo.m_nSendTimeout      = 1000;
            m_configInfo.m_nRecvTimeout      = 1000;

            return true;
        }

        public bool Initialize()
        {
            bool bRet = LoadConfig();
            if (!bRet)
            {
                System.Console.WriteLine("initialize failed, LoadConfig");
                return false;
            }
            m_localEndPoint = new IPEndPoint(
                m_configInfo.m_nListenAddr, 
                m_configInfo.m_nListenPort
                );

            //预分配对象
            InitSocketInfo();
            m_recvArgsPool = new SocketAsyncEventArgsPool(m_configInfo.m_nMaxConnClients);
            for (int i = 0; i < m_configInfo.m_nMaxConnClients; i++)
            {
                SocketAsyncEventArgs args = new SocketAsyncEventArgs();
                args.UserToken = new int();
                args.Completed += new EventHandler<SocketAsyncEventArgs>(IO_Completed);
                m_recvArgsPool.Push(args);
            }

            m_sendArgsPool = new SocketAsyncEventArgsPool(m_configInfo.m_nMaxConnClients);
            for (int i = 0; i < m_configInfo.m_nMaxConnClients; i++)
            {
                SocketAsyncEventArgs args = new SocketAsyncEventArgs();
                args.UserToken = new int();
                args.Completed += new EventHandler<SocketAsyncEventArgs>(IO_Completed);
                m_sendArgsPool.Push(args);
            }
            //创建逻辑处理dll
            m_handleServer = IMLogicMgr.CreateLogicServer(this);
            if (m_handleServer == null)
            {
                string str = "load logic dll failed";
                WriteErrorLog(str);
                return false;
            }
            return true ;
        }

        public void StartServer()
        {
            m_listenSocket = new Socket(
                m_localEndPoint.AddressFamily, 
                SocketType.Stream, 
                ProtocolType.Tcp
                );
            m_listenSocket.Bind(m_localEndPoint);
            m_listenSocket.Listen(100);

            PostAccept(null);
            //启动超时检测线程,防止恶意攻击
            ThreadStart ts = new ThreadStart(CheckTimeout);
            Thread t = new Thread(ts);
            t.Start();
        }

        private void InitSocketInfo()
        {
            m_nClientSocketCount = 0;
            //初始化个套接字信息结构
            m_socketInfos = new SocketInfo[m_configInfo.m_nMaxConnClients];
            for (int i = 0; i < m_configInfo.m_nMaxConnClients; i++)
            {
                m_socketInfos[i].Init(
                    m_configInfo.m_nSocketSendBufLen,
                    m_configInfo.m_nSocketRecvBufLen
                    );

                m_socketInfos[i].m_netHeader.m_nSocketIndex = i;
                m_socketInfos[i].m_nNextIndex = i + 1;
                m_socketInfos[i].m_nPrevIndex = i - 1;
            }
            m_socketInfos[m_configInfo.m_nMaxConnClients - 1].m_nNextIndex = -1;
            m_nFreeHeaderIndex = 0;
            m_nUsedHeaderIndex = -1;
        }

        private void PostAccept(SocketAsyncEventArgs acceptArgs)
        {
            if (acceptArgs == null)
            {
                acceptArgs = new SocketAsyncEventArgs();
                acceptArgs.Completed += new EventHandler<SocketAsyncEventArgs>
                    (Accept_Completed);
            }
            else
            {
                acceptArgs.AcceptSocket = null;
            }
            bool willRaiseEvent = m_listenSocket.AcceptAsync(acceptArgs);
            if (!willRaiseEvent)
            {
                ProcessAccept(acceptArgs);
            }
        }

        void Accept_Completed(object sender, SocketAsyncEventArgs e)
        {
            ProcessAccept(e);
        }

        private void ProcessAccept(SocketAsyncEventArgs e)
        {
            //搜索一个空闲的socket结构
            int nIndex = CreateSocketInfo();
            if (nIndex == -1)
            {
                string strErr = "createsocketinfo invalid index " + nIndex;
                WriteErrorLog(strErr);
            }
            else 
            {
                m_socketInfos[nIndex].m_netHeader.m_createTime = DateTime.Now.ToFileTime();
                m_socketInfos[nIndex].m_netHeader.m_nSocketIndex = nIndex;
                m_socketInfos[nIndex].m_netHeader.m_uSocketCount = ++m_nClientSocketCount;

                m_socketInfos[nIndex].m_bSendData    = false;
                m_socketInfos[nIndex].m_lastRecvTime = DateTime.Now;
               
                m_socketInfos[nIndex].m_socket     = e.AcceptSocket;
                m_socketInfos[nIndex].m_recvSocketArgs = m_recvArgsPool.Pop();
                m_socketInfos[nIndex].m_sendSocketArgs = m_sendArgsPool.Pop();

                m_socketInfos[nIndex].m_nReadBeginIndex = NetHeader.SIZE;
                m_socketInfos[nIndex].m_nReadEndIndex   = NetHeader.SIZE;

                //设置iocp的缓冲区
                m_socketInfos[nIndex].m_recvSocketArgs.SetBuffer(m_socketInfos[nIndex].m_szRecvBuffer, NetHeader.SIZE, m_configInfo.m_nSocketRecvBufLen - NetHeader.SIZE);
                m_socketInfos[nIndex].m_sendSocketArgs.SetBuffer(m_socketInfos[nIndex].m_szSendBuffer, 0, m_configInfo.m_nSocketSendBufLen);

                m_socketInfos[nIndex].m_recvSocketArgs.UserToken = nIndex;
                m_socketInfos[nIndex].m_sendSocketArgs.UserToken = nIndex;

                bool bRet = m_socketInfos[nIndex].m_socket.ReceiveAsync(m_socketInfos[nIndex].m_recvSocketArgs);
                if (!bRet)
                {
                    ReceiveClientData(m_socketInfos[nIndex].m_recvSocketArgs);
                }
            }
            PostAccept(e);
        }

        private int CreateSocketInfo()
        {
            int nFreeIndex = -1;
            lock (m_socketInfos)
            {
                if (m_nFreeHeaderIndex >= 0)
                {
                    nFreeIndex = m_nFreeHeaderIndex;
                    m_nFreeHeaderIndex = m_socketInfos[m_nFreeHeaderIndex].m_nNextIndex;
                    m_socketInfos[nFreeIndex].m_nNextIndex = -1;
                }
                if (nFreeIndex != -1)
                {
                    m_socketInfos[nFreeIndex].m_nNextIndex = m_nUsedHeaderIndex;
                    if (m_nUsedHeaderIndex != -1)
                    {
                        m_socketInfos[m_nUsedHeaderIndex].m_nPrevIndex = nFreeIndex;
                    }
                    m_nUsedHeaderIndex = nFreeIndex;
                    m_socketInfos[nFreeIndex].m_bUsed = true;
                }
            }
            return nFreeIndex;
        }

        private void  ReceiveClientData(SocketAsyncEventArgs e)
        {
            int nIndex = (int)e.UserToken;
            if (nIndex < 0 || nIndex > m_configInfo.m_nMaxConnClients)
            {
                return;
            }
            if (!m_socketInfos[nIndex].m_bUsed)
            {
                ClearSocketInfo(nIndex);
                return;
            }
            try
            {
                if (e.BytesTransferred > 0 && e.SocketError == SocketError.Success)
                {
                    m_socketInfos[nIndex].m_lastRecvTime = DateTime.Now;
                    m_socketInfos[nIndex].m_nReadEndIndex += e.BytesTransferred;
                    UInt32 nLeftLen = (UInt32)(m_socketInfos[nIndex].m_nReadEndIndex - m_socketInfos[nIndex].m_nReadBeginIndex);

                    //分包处理
                    while (true)
                    {
                        if (nLeftLen <= 0)
                        {
                            break;
                        }
                        UInt32 nPackLen = m_handleServer.GetPackageLen(
                            m_socketInfos[nIndex].m_szRecvBuffer,
                            m_socketInfos[nIndex].m_nReadBeginIndex,
                            nLeftLen
                            );
                        if (nPackLen > m_configInfo.m_nMaxClientLen)
                        {
                            //客户端发送的包太大了，忽略
                            string strErr = "client package too big, " + nPackLen;
                            WriteErrorLog(strErr);
                            continue;
                        }
                        
                        if (nPackLen == 0)
                        {
                            break;
                        }
                        if (nPackLen > nLeftLen)
                        {
                            string strInfo = "recv part package, left " + (nPackLen - nLeftLen);
                            WriteInfoLog(strInfo);
                            break;
                        }
                        nLeftLen -= nPackLen;
                        m_socketInfos[nIndex].m_netHeader.m_nRecvPackCount++;
                        //进行包处理,写入自定义包头
                        m_socketInfos[nIndex].m_netHeader.ToBytes(
                            m_socketInfos[nIndex].m_szRecvBuffer,
                            m_socketInfos[nIndex].m_nReadBeginIndex - NetHeader.SIZE
                            );
                        //写入协议数据
                        m_handleServer.OnReceiveFromClient(
                            m_socketInfos[nIndex].m_szRecvBuffer,
                            m_socketInfos[nIndex].m_nReadBeginIndex - NetHeader.SIZE,
                            nPackLen + (uint)NetHeader.SIZE
                            );
                        m_socketInfos[nIndex].m_nReadBeginIndex += (int)nPackLen;
                    }
                    if (nLeftLen == 0)
                    {
                        m_socketInfos[nIndex].m_nReadBeginIndex = NetHeader.SIZE;
                        m_socketInfos[nIndex].m_nReadEndIndex   = NetHeader.SIZE;
                    }
                    else
                    {
                        Array.Copy(
                            m_socketInfos[nIndex].m_szRecvBuffer,
                            m_socketInfos[nIndex].m_nReadBeginIndex,
                            m_socketInfos[nIndex].m_szRecvBuffer,
                            NetHeader.SIZE,
                            nLeftLen
                            );
                        m_socketInfos[nIndex].m_nReadEndIndex = (int)nLeftLen + NetHeader.SIZE;
                    }
                    e.SetBuffer(m_socketInfos[nIndex].m_nReadEndIndex, m_configInfo.m_nSocketRecvBufLen - m_socketInfos[nIndex].m_nReadEndIndex);
                    bool bRet = m_socketInfos[nIndex].m_socket.ReceiveAsync(e);
                    if (!bRet)
                    {
                        ReceiveClientData(e);
                    }
                }
                else
                {
                    ClearSocketInfo(nIndex);
                }
            }
            catch (Exception e1)
            {
                WriteInfoLog(e1.Message);
               ClearSocketInfo(nIndex);
            }
        }

        private void WriteInfoLog(string strInfo)
        {
            
        }

        private void WriteErrorLog(string strErr)
        {
 
        }

        private void ClearSocketInfo(int nIndex)
        { 
            if (nIndex < 0 || nIndex > m_configInfo.m_nMaxConnClients)
            {
                string str = "clearsocketinfo , invalid index " + nIndex;
                WriteInfoLog(str);
                return;
            } 
            lock (m_socketInfos)
            {
                if (nIndex == m_nUsedHeaderIndex)
                {
                    m_nUsedHeaderIndex = m_socketInfos[m_nUsedHeaderIndex].m_nNextIndex;
                    if (m_nUsedHeaderIndex != -1)
                    {
                        m_socketInfos[m_nUsedHeaderIndex].m_nPrevIndex = -1;
                    }
                }
                else
                {
                    m_socketInfos[m_socketInfos[nIndex].m_nPrevIndex].m_nNextIndex =
                        m_socketInfos[nIndex].m_nNextIndex;

                    if (m_socketInfos[nIndex].m_nNextIndex != -1)
                    {
                        m_socketInfos[m_socketInfos[nIndex].m_nNextIndex].m_nPrevIndex =
                            m_socketInfos[nIndex].m_nPrevIndex;
                    }
                }
                m_socketInfos[nIndex].m_nNextIndex = m_nFreeHeaderIndex;
                if (m_nFreeHeaderIndex != -1)
                {
                    m_socketInfos[m_nFreeHeaderIndex].m_nPrevIndex = nIndex;
                }
               
                m_socketInfos[nIndex].m_nPrevIndex = -1;

                m_nFreeHeaderIndex = nIndex;
                m_socketInfos[nIndex].m_recvSocketArgs.UserToken = -1;
                m_recvArgsPool.Push(m_socketInfos[nIndex].m_recvSocketArgs); //回收

                m_socketInfos[nIndex].m_sendSocketArgs.UserToken = -1;
                m_sendArgsPool.Push(m_socketInfos[nIndex].m_sendSocketArgs); //回收

                Socket s = m_socketInfos[nIndex].m_socket;
                CloseSocket(s);

                m_socketInfos[nIndex].Clear();
            }
        }

        private void CloseSocket(Socket s)
        {
            try
            {
                s.Shutdown(SocketShutdown.Both);

            }
            catch (Exception)
            {
            }
            finally
            {
                s.Close();
            }
        }

        private void CheckTimeout()
        {
            while (true)
            {
                Thread.Sleep(m_configInfo.m_nCheckSocketTime * 1000);
                lock (m_socketInfos)
                {
                    int nIndex = m_nUsedHeaderIndex;
                    while (nIndex != -1 && m_socketInfos[nIndex].m_bUsed)
                    {
                        TimeSpan diffActive = DateTime.Now - m_socketInfos[nIndex].m_lastRecvTime;
                        if (m_socketInfos[nIndex].m_bSendData)
                        {
                            if (diffActive.Seconds > m_configInfo.m_nSocketTimeout)
                            {
                                string str = "client has not send a package in " + diffActive + "seonds";
                                WriteInfoLog(str);
                                Socket s = m_socketInfos[nIndex].m_socket;
                                m_socketInfos[nIndex].m_bUsed = false;
                                CloseSocket(s);
                            }
                        }
                        else
                        {     
                            if (diffActive.Seconds > m_configInfo.m_nConnTimeout)
                            {
                                string str = "client connect server, has not send a package " + diffActive + "seonds";
                                WriteInfoLog(str);
                                m_socketInfos[nIndex].m_bUsed = false;
                                Socket s = m_socketInfos[nIndex].m_socket;
                                CloseSocket(s);
                            }
                        }
                        nIndex = m_socketInfos[nIndex].m_nNextIndex;
                    }
                }
            }
        }

        void ProcessSendData(SocketAsyncEventArgs e)
        {
            if (e.SocketError == SocketError.Success)
            {

            }
            else
            {
                ClearSocketInfo((int)e.UserToken);
            }
        }

        void IO_Completed(object sender, SocketAsyncEventArgs e)
        {
            switch (e.LastOperation)
            {
                case SocketAsyncOperation.Receive:
                    ReceiveClientData(e);
                    break;
                case SocketAsyncOperation.Send:
                    ProcessSendData(e);
                    break;
                default:
                    break;
            }
        }

        private int ProcessLogicRequest(int nIndex, ref NetHeader header)
        {
            //逻辑层要求关闭socket
            if ((header.m_nInnerFlag & InnerFlag.INNERFLAG_LOGIC_REQUEST_CLOSE_SOCKET) ==
                InnerFlag.INNERFLAG_LOGIC_REQUEST_CLOSE_SOCKET)
            {
                 ClearSocketInfo(nIndex);
                 return 0;
            }
            //逻辑层要求设置用户数据
            if ((header.m_nInnerFlag & InnerFlag.INNERFLAG_SET_USER_DATA) ==
                InnerFlag.INNERFLAG_SET_USER_DATA)
            {
                m_socketInfos[nIndex].m_netHeader.m_userData = header.m_userData;
                m_socketInfos[nIndex].m_netHeader.m_nInnerFlag |= InnerFlag.INNERFLAG_HAVE_USER_DATA;
            }
            return 0;
        }
        //同步发送
        public int  OnSendToClient(byte[] bData, int nDataLen, ref NetHeader header)
        {
            int nIndex = header.m_nSocketIndex;
            if (m_socketInfos[nIndex].m_netHeader.m_createTime !=
                header.m_createTime ||
                m_socketInfos[nIndex].m_netHeader.m_uSocketCount !=
                header.m_uSocketCount)
            {
                string str = "invalid index " + nIndex;
                WriteInfoLog(str);
                return -1;
            }
            //逻辑层和imserver之间的消息
            if (nDataLen == NetHeader.SIZE)
            {
                return ProcessLogicRequest(nIndex, ref header);
            }          
            //异步发送数据
            try
            {
                lock (m_socketInfos[nIndex].m_socket)
                {
                    m_socketInfos[nIndex].m_sendSocketArgs.SetBuffer(0, nDataLen);
                    Array.Copy(bData, 0, m_socketInfos[nIndex].m_szSendBuffer, 0, nDataLen);

                    bool bRet = m_socketInfos[nIndex].m_socket.SendAsync(m_socketInfos[nIndex].m_sendSocketArgs);
                    if (!bRet)
                    {
                        ProcessSendData(m_socketInfos[nIndex].m_sendSocketArgs);
                    }
                }
            }
            catch (SocketException e)
            {
                string str = "senddata failed socket index " + nIndex;
                WriteInfoLog(str);
                ClearSocketInfo(nIndex);
            }
            catch (Exception e)
            {
                WriteInfoLog(e.Message);
                ClearSocketInfo(nIndex);
            }
            return 0;
        }
    }
}
